package com.wxxymaker.edu.controller.video;

import com.blade.ioc.annotation.Inject;
import com.blade.kit.EncryptKit;
import com.blade.kit.StringKit;
import com.blade.mvc.annotation.*;
import com.blade.mvc.multipart.FileItem;
import com.blade.mvc.ui.RestResponse;
import com.wxxymaker.edu.model.entity.Material;
import com.wxxymaker.edu.service.MaterialService;
import com.wxxymaker.edu.utils.Const;
import com.wxxymaker.edu.utils.FileUtils;
import com.wxxymaker.edu.utils.TokenUtils;
import com.wxxymaker.edu.utils.enums.MaterialType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;

/**
 * @AUTHOR soft
 * @DATE 2019/3/7 22:12
 * @DESCRIBE 视频上传等相关处理
 * 支持切片上传，断点续传，甚至是生成m3u8
 */
@Slf4j
@Path("/video")
public class VideoController {
    // 视频存放目录，1%s代表课程id 2%s代表视频文件名
    private static final String VIDEO_PATH = "/video/course/%s/task/%s";

    @Inject
    private MaterialService materialService;

    /**
     * 视频切片上传
     *
     * @param file     文件切片
     * @param filename 文件名
     * @param size     文件总大小
     * @param index    第几片
     * @param total    总片数
     * @param kid      课程id
     */
    @PostRoute("/upload")
    @JSON
    public RestResponse upload(@MultipartParam("file_data") FileItem file,
                               @Param(name = "file_name") String filename,
                               @Param(name = "file_size") Long size,
                               @Param(name = "file_total") Integer total,
                               @Param(name = "file_index") Integer index,
                               @Param(name = "file_new") String newFilename,
                               @Param Integer kid) {
        try {
            if (file != null) {
                if (StringKit.isEmpty(newFilename)) {
                    newFilename = FileUtils.getRandomFilename(filename);
                }
                File target = new File(Const.CLASSPATH, String.format(VIDEO_PATH, kid, newFilename));
                if (!target.exists()) {
                    FileUtils.createFile(target);
                    file.moveTo(target);
                } else {
                    Files.write(target.toPath(), file.getData(), StandardOpenOption.APPEND);
                }
                if (index >= total) {
                    return RestResponse.ok(saveToDb(kid, size, filename, newFilename));
                }
                return RestResponse.ok(new Slice(total, index, newFilename), 206);
            }
        } catch (IOException e) {
            log.error("|-|分片文件上传失败 --> {}", e.getMessage());
        }
        return RestResponse.fail("上传失败！");
    }

    private String getNewFilename(String filename, String name) {
        String type = filename.substring(filename.lastIndexOf("."));
        String md5 = EncryptKit.md5(filename, name);
        return md5 + type;
    }

    /**
     * 保存视频文件
     *
     * @param kid         课程id
     * @param size        文件大小
     * @param oldName     原文件名
     * @param newFilename 新的随机文件名
     */
    private Material saveToDb(Integer kid, long size, String oldName, String newFilename) {
        Integer uid = TokenUtils.currentUser().getId();
        Material material = new Material();
        material.setCourseId(kid);
        material.setUserId(uid);
        material.setDowns(0);
        material.setSize((size / 1024.0 / 1024.0));
        material.setFilename(oldName);
        material.setType(MaterialType.TASK);
        String videoPath = "/file/video/" + kid + "?v=" + newFilename;
        material.setPath(videoPath);
        return materialService.add(material);
    }

    @Data
    @AllArgsConstructor
    static class Slice {
        private Integer total;
        private Integer index;
        private String filename;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private class UploadResult {
        private Integer id;       // 资源id
        private String path;     // web路径
        private String filename; // 文件名
        private Object payload;  // 携带的数据
    }
}
